package com.hmdp.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hmdp.domain.dto.Result;
import com.hmdp.domain.entity.Shop;
import com.hmdp.domain.entity.ShopType;
import com.hmdp.mapper.ShopTypeMapper;
import com.hmdp.service.IShopTypeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.domain.vo.RedisShopTypeList;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

import static com.hmdp.utils.RedisConstants.CACHE_SHOPTYPE_KEY;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
@Slf4j
public class ShopTypeServiceImpl extends ServiceImpl<ShopTypeMapper, ShopType> implements IShopTypeService {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    ShopServiceImpl shopService;
    ReentrantLock reentrantLock;
    ExecutorService executorService = Executors.newFixedThreadPool(1);

    /**
     * 查询所有类型
     * @return
     */
    @Override
    public Result queryTypeList() {
        String shopTypeListJson = stringRedisTemplate.opsForValue().get(CACHE_SHOPTYPE_KEY);
        RedisShopTypeList redisShopTypeList = JSONUtil.toBean(shopTypeListJson, RedisShopTypeList.class);
        if (CollUtil.isEmpty(redisShopTypeList.getShopTypes())) {
            return Result.fail("类型信息为空");
        }
        if (redisShopTypeList.getExpireTime()){
            if (reentrantLock.tryLock()) {
                executorService.execute(()->{
                    try {
                        //逻辑过期更新缓存
                        logicalExpire();
                    }finally {
                        reentrantLock.unlock();
                    }
                });
            }
        }
        return Result.ok(redisShopTypeList.getShopTypes());
    }

    /**
     * 通过商铺类型id查询某些商铺
     *
     * @param typeId
     * @return
     */
    @Override
    public Result queryById(Long typeId) {
        ArrayList<Shop> shops = (ArrayList<Shop>) shopService.list(new QueryWrapper<Shop>().eq("type_id", typeId));
        return Result.ok(shops);
    }

    /**
     * 更新店铺类型数据
     * @param shopType
     * @return
     */
    @Override
    public Result updateShopType(ShopType shopType) {
        updateById(shopType);
        redisCacheExpired();
        return Result.ok();
    }

    /**
     * 添加店铺类型
     * @param shopType
     * @return
     */
    @Override
    public Result insert(ShopType shopType) {
        save(shopType);
        redisCacheExpired();
        return Result.ok();
    }

    private void redisCacheExpired() {
        String shopTypeJson = stringRedisTemplate.opsForValue().get(CACHE_SHOPTYPE_KEY);
        RedisShopTypeList redisShopTypeList = JSONUtil.toBean(shopTypeJson, RedisShopTypeList.class);
        redisShopTypeList.setExpireTime(true);
        stringRedisTemplate.opsForValue().set(CACHE_SHOPTYPE_KEY,JSONUtil.toJsonStr(redisShopTypeList));
    }

    /**
     * 预热类型信息
     */
    @PostConstruct
    public void cachedReservation() {
        logicalExpire();
        log.info("商铺类型数据预热完成");
    }

    private void logicalExpire() {
        ArrayList<ShopType> typeList =
                (ArrayList<ShopType>) query().select("id", "name", "icon", "sort").orderByAsc("sort").list();
        RedisShopTypeList shopTypeList = RedisShopTypeList.builder()
                .shopTypes(typeList)
                .expireTime(false)
                .build();
        stringRedisTemplate.opsForValue().set(CACHE_SHOPTYPE_KEY, JSONUtil.toJsonStr(shopTypeList));
    }
}
